home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
ARASAN_S.ZIP
/
MAKEBOOK.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-03
|
8KB
|
331 lines
// Copyright 1994 by Jon Dart. All Rights Reserved.
// Stand-alone executable to build the binary opening book from
// a text file.
// There are two book files, one for moves by White and one for
// Black. Each book consists of three portions: a header, a hash
// table, and an array of book entries.
// The header is 8 bytes:
// offset
// 0 version number
// 1-2 hash table size
// 3-4 number of book entries
// 5-7 unused
// The hash table is an array of unsigned indexes into the book
// entry array. A hash code for the position modulo the hash table
// size is used to look up in this array the first book entry for the
// position.
// The book entries themselves are structures defined in bookentr.h.
// Each one is 8 bytes and contains the full hash code, the move
// index, a weight indicating how often the computer should play the
// move, and an index to the next entry in the hash chain.
// Each book is limited to 65536 bytes, enough to hold slightly over
// 8000 moves.
#include "board.h"
#include "array.h"
#include "emove.h"
#include "bookentr.h"
// #include "bookwrit.h"
#include "hash.h"
#include "bhash.h"
#include "movegen.h"
#include "notation.h"
#include "types.h"
extern "C"
{
#include <string.h>
#include <ctype.h>
#include <assert.h>
};
#include <fstream.h>
#include <iostream.h>
const unsigned MAX_MOVES = 8050;
const unsigned HASH_TABLE_SIZE = 511;
struct book_info
{
unsigned next_free;
Array < unsigned >*hash_table;
Array < Book_Entry * >*book_moves;
};
static book_info book_data[2];
const int Entry_Size = sizeof(Book_Entry);
const int Header_Size = 8;
const int Buffer_Size = 4096;
const byte Book_Version = 2;
static Boolean
search(const unsigned start, const unsigned move_index,
const ColorType side,
const unsigned long hc)
{
unsigned indx = start;
byte hibytes[3];
Book_Entry be(hc, 0, move_index, 0);
while (indx != INVALID)
{
assert(indx < MAX_MOVES);
Book_Entry *entry = (*(book_data[side].book_moves))[indx];
if (*entry == be && entry->move_index == move_index)
return True;
indx = entry->next;
}
return False;
}
static void
add_move(const Board & board, int move_index, int recommend)
{
unsigned probe = (unsigned) (Board_Hash::HashCode2(board) % HASH_TABLE_SIZE);
unsigned hit = (*(book_data[board.Side()].hash_table))[probe];
if (hit == INVALID || !search(hit, move_index, board.Side(),
board.HashCode()))
{
Book_Entry *new_entry = new Book_Entry(board.HashCode(), recommend,
move_index, hit);
assert(new_entry);
unsigned next = book_data[board.Side()].next_free;
(*(book_data[board.Side()].book_moves))[next] = new_entry;
(*(book_data[board.Side()].hash_table))[probe] = next;
#ifdef DEBUG
cout << "p:" << probe << " h:" << board.HashCode() << " i:"
<< move_index << " f:" << next << endl;
#endif
book_data[board.Side()].next_free++;
}
}
static void
write_book(const ColorType side)
{
byte *write_buffer = new byte[Buffer_Size];
assert(write_buffer);
static char *Book_File_Name[2] = {"bookb", "bookw"};
ofstream book_file(Book_File_Name[side],
#ifdef __BORLANDC__
ios::out | ios::trunc | ios::binary);
#else
ios::out | ios::trunc);
#endif
if (!book_file.good())
return;
// write the header
book_file.put((char)Book_Version);
unsigned ht_size = HASH_TABLE_SIZE;
book_file.write((char *) &ht_size, (int) sizeof(unsigned));
book_file.write((char *) (&(book_data[side].next_free)),
(int) sizeof(unsigned));
// pad out the header to 8 bytes:
char stuff[3] = {'\0', '\0', '\0'};
book_file.write(stuff, 3);
// write the hash table
for (int i = 0; i < HASH_TABLE_SIZE; i++)
{
unsigned ht_entry = (*(book_data[side].hash_table))[i];
book_file.put((char)(ht_entry % 256));
book_file.put((char)(ht_entry / 256));
}
// write the book moves
unsigned index = 0;
unsigned limit = book_data[side].next_free;
for (i = 0; i < limit; i++)
{
if (index + sizeof(Book_Entry) <= Buffer_Size)
{
memcpy(write_buffer + index,
(*(book_data[side].book_moves))[i], sizeof(Book_Entry));
index += sizeof(Book_Entry);
} else
{
unsigned to_go = Buffer_Size - index;
memcpy(write_buffer + index,
(*(book_data[side].book_moves))[i], to_go);
book_file.write(write_buffer, Buffer_Size);
memcpy(write_buffer,
(*(book_data[side].book_moves))[i] + to_go, sizeof(Book_Entry) - to_go);
index = sizeof(Book_Entry) - to_go;
}
}
if (index)
book_file.write(write_buffer, index);
book_file.close();
delete[] write_buffer;
cout << book_data[side].next_free << " moves in "
<< side << " book." << endl;
}
int
main(int argc, char **argv)
{
char book_name[128];
fstream infile;
if (argc < 2)
strcpy(book_name, "BOOK.TXT");
else
strcpy(book_name, argv[1]);
infile.open(book_name, ios::in);
if (!infile.good())
{
cerr << "Can't open book file: " << book_name << endl;
return -1;
}
book_data[White].book_moves = new Array < Book_Entry * >(MAX_MOVES, False);
book_data[Black].book_moves = new Array < Book_Entry * >(MAX_MOVES, False);
book_data[White].hash_table = new Array < unsigned >(HASH_TABLE_SIZE, False);
book_data[Black].hash_table = new Array < unsigned >(HASH_TABLE_SIZE, False);
book_data[White].next_free = 0;
book_data[Black].next_free = 0;
char buf[128];
char movebuf[20];
unsigned line = 0;
char *q;
Board board;
Board tmpboard;
int recommend;
Move moves[Move_Generator::MaxMoves];
int dots = 0;
for (unsigned i = 0; i < HASH_TABLE_SIZE; i++)
{
(*(book_data[White].hash_table))[i] = INVALID;
(*(book_data[Black].hash_table))[i] = INVALID;
}
for (i = 0; i < MAX_MOVES; i++)
{
(*(book_data[White].book_moves))[i] = NULL;
(*(book_data[Black].book_moves))[i] = NULL;
}
while (!infile.eof() && book_data[White].next_free < MAX_MOVES
&& book_data[Black].next_free < MAX_MOVES)
{
recommend = 5;
infile.getline(buf, 128);
#ifdef DEBUG
cout << buf << endl;
#endif
line++;
char *p = buf;
while (isspace(*p))
p++;
switch (*p)
{
case '\0':
continue;
case ';':
continue;
case 'm':
tmpboard = board;
continue;
case 'r':
board = tmpboard;
continue;
case 's':
case 't':
break; // these are obsolete
case '-':
board.Reset();
break;
default:
{
while (*p)
{
while (isspace(*p))
p++;
if (*p == '\0')
break;
q = movebuf;
int count = 0;
while (!isspace(*p) && *p && count < 19)
{
*q++ = *p++;
++count;
}
*q = '\0';
Move move = Notation::Value(board, board.Side(), movebuf);
if (move.IsNull())
{
cerr << endl << "Illegal move in file, line " <<
line << " (" << movebuf << ")" << endl;
infile.close();
return -1;
}
ExtendedMove emove(board, move);
// check (pseudo) legality:
Move_Generator mg(board, 0, Move::NullMove());
int found = 0;
int move_indx = 0;
int n = mg.Generate_Moves(moves, False, True);
for (int i = 0; i < n; i++)
{
if (moves[i] == emove)
{
move_indx = i;
found++;
break;
}
}
if (!found)
{
cerr << endl << "Illegal move in file, line " << line << " ("
<< movebuf << ")" << endl;
infile.close();
return -1;
}
dots++;
if (dots % 50 == 0)
cout << '.';
if (dots > 3000)
{
cout << endl;
dots = 1;
}
while (isspace(*p))
p++;
if (*p)
{
if ((*p >= '0') && (*p <= '9'))
{
recommend = *p - '0';
p++;
}
}
add_move(board, move_indx, recommend);
board.MakeMove(emove);
}
}
}
}
infile.close();
cout << endl;
write_book(White);
write_book(Black);
return 0;
}